<template>
    <div class="dp_mask fe-datetimepikcer-wrapper" v-show="selfShow">
        <div class="dp_select showPicker picker-columns">
            <header>
                <button class="nav_left picker-cancel" @click="cancel">取消</button>
                <slot></slot><!-- 这里插入标题的内容 -->
                <button class="nav_right picker-ok" @click="confirm">确定</button>
            </header>
            <div class="ub" id="wrapper-parent">
                <div class="ub-f1 picker-wrapper" id="yearId" :ref="yearId" v-on:touchstart.stop.prevent="touchStartItem($event,containerOptions.yearContainer,1)" v-on:touchmove.stop.prevent="touchMoveItem($event,containerOptions.yearContainer,1)" v-on:touchend.stop.prevent="touchEndItem($event,containerOptions.yearContainer,1)">
                    <ul v-bind:style="{
                        transition:yearTransition,
                        transform:yearTransform}">
                        <li></li>
                        <li></li>
                        <li v-for="item in years" :key="item">
                            {{item}}
                        </li>
                        <li></li>
                        <li></li>
                    </ul>
                </div>
                <div class="ub-f1 picker-wrapper" id="monthId" :ref="monthId" v-on:touchstart.stop.prevent="touchStartItem($event,containerOptions.monthContainer,2)" v-on:touchmove.stop.prevent="touchMoveItem($event,containerOptions.monthContainer,2)" v-on:touchend.stop.prevent="touchEndItem($event,containerOptions.monthContainer,2)">
                    <ul v-bind:style="{
                        transition:monthTransition,
                        transform:monthTransform}">
                        <li></li>
                        <li></li>
                        <li v-for="item in months" :key="item">
                            {{item}}
                        </li>
                        <!-- <li data-value="01">01月</li>                         
                        <li data-value="01">02月</li>
                        <li data-value="01">03月</li> -->
                        <li></li>
                        <li></li>
                    </ul>
                </div>
                <div class="ub-f1 picker-wrapper" v-if="type.toString() == 1" id="dateId" :ref="dateId" v-on:touchstart.stop.prevent="touchStartItem($event,containerOptions.dateContainer,3)" v-on:touchmove.stop.prevent="touchMoveItem($event,containerOptions.dateContainer,3)" v-on:touchend.stop.prevent="touchEndItem($event,containerOptions.dateContainer,3)">
                    <ul v-bind:style="{
                        transition:dateTransition,
                        transform:dateTransform}">
                        <li></li>
                        <li></li>
                        <li v-for="item in dates" :key="item">
                            {{item}}
                        </li>
                        <!-- <li data-value="01">01日</li>                        
                        <li data-value="01">02日</li>  
                        <li data-value="01">03日</li>   -->
                        <li></li>
                        <li></li>
                    </ul>
                </div>
                <div class="sel_top"></div>
                <div class="sel_bottom"></div>
                <div class="sel_middle"></div>
            </div>
        </div>
    </div>
</template>

<script>
    let currentDate = new Date();
    let currentDateDetail = { year: currentDate.getFullYear(), month: currentDate.getMonth() + 1, date: currentDate.getDate() };
    currentDateDetail.month = currentDateDetail.month < 10 ? '0' + currentDateDetail.month : currentDateDetail.month;
    currentDateDetail.date = currentDateDetail.date < 10 ? '0' + currentDateDetail.date : currentDateDetail.date;
    export default {
        name: "v-date-picker",
        props: {
            type: {
                type: Number,
                required: true,
                default: 1 //1 年月日  2 年月
            },
            title: {
                type: String,
                default: "请选择日期"
            },
            isShow: {
                type: Boolean,
                required: true,
                default: false
            },
            maxYear: {
                type: Number,
                default: currentDateDetail.year + 100 //默认最长年份当前年份向后100年
            },
            minYear: {
                type: Number,
                default: currentDateDetail.year - 100 //默认最前年份当前年份向前100年
            },
            separator: {
                type: String,
                default: "-" //默认日期的分隔符
            },
            value: {
                type: String,
                default: function() {
                    let separatorFlag = this.separator;
                    let defaultValue = currentDateDetail.year + separatorFlag + currentDateDetail.month + separatorFlag + currentDateDetail.date;
                    return defaultValue; //插件默认日期为当前日期
                }
            },
            yearId: {
                type: String,
                default: function() {
                    return 'fe-picker-year-id-' + this._uid;
                }
            },
            monthId: {
                type: String,
                default: function() {
                    return 'fe-picker-month-id-' + this._uid;
                }
            },
            dateId: {
                type: String,
                default: function() {
                    return 'fe-picker-date-id-' + this._uid;
                }
            }
        },
        data() {
            let years = this.getRangeArray(this.minYear, this.maxYear);
            let months = this.getRangeArray(1, 12, true);
            let seletedDateDetail = this.getDateDetail();
            let dates = this.getRangeArray(1, this.getMonthMaxDay(seletedDateDetail.year, seletedDateDetail.month), true);
            let containerOptions = {
                yearContainer: this.getContainerOptions(),
                monthContainer: this.getContainerOptions(),
                dateContainer: this.type.toString() === '1' ? this.getContainerOptions() : {}
            };
            // containerOptions = this.getHeights(containerOptions);
            return {
                years: years,
                months: months,
                dates: dates,
                year: seletedDateDetail.year,
                month: seletedDateDetail.month,
                date: seletedDateDetail.date,
                yearTransition: 'none',
                yearTransform: 'none',
                monthTransition: 'none',
                monthTransform: 'none',
                dateTransition: 'none',
                dateTransform: 'none',
                containerOptions: containerOptions,
                childShow: this.isShow
            };
        },
        beforeCreate() {},
        mounted() {},
        computed: {
            selfShow: {
                get() {
                    this.childShow = this.isShow;
                    return this.childShow;
                },
                set(val) {
                    this.childShow = val;
                }
            }
        },
        watch: {
            childShow(currentVal, oldVal) {
                if (currentVal) {
                    if (this.childShow) {
                        this.containerOptions = this.getHeights(this.containerOptions);
                        let beforeSelected = this.getDateDetail();
                        let yearDefaultLen = this.containerOptions.yearContainer.stepLen * (this.years.indexOf(beforeSelected.year));
                        let monthDefaultLen = this.containerOptions.monthContainer.stepLen * (this.months.indexOf(beforeSelected.month));
                        this.setScrollTo(1, this.containerOptions.yearContainer, yearDefaultLen);
                        this.setScrollTo(2, this.containerOptions.monthContainer, monthDefaultLen);
                        if (this.type.toString() === '1') {
                            let dateDefaultLen = this.containerOptions.dateContainer.stepLen * (this.dates.indexOf(beforeSelected.date));
                            this.setScrollTo(3, this.containerOptions.dateContainer, dateDefaultLen);
                        }
                    }
                }
            }
        },
        methods: {
            touchStartItem(e, containerOption, containerTransition, columnsType) {
                if (containerOption) {
                    containerOption.startTime = parseInt(new Date().getTime());
                    let touches = e.touches ? e.touches[0] : e;
                    containerOption.startPageY = touches.pageY; //起始触摸点
                    let transitionStyle = 'none';
                    this.setTransition(columnsType, true, transitionStyle);
                }
            },
            touchMoveItem(e, containerOption, columnsType) {
                if (containerOption) {
                    let timestamp = parseInt(new Date().getTime());
                    let touches = e.touches ? e.touches[0] : e;
                    // 滚动高度
                    let diffPageY = touches.pageY - containerOption.startPageY;
                    let movePageY = diffPageY + containerOption.offsetTop;

                    // 最少移动10px
                    if (timestamp - containerOption.endTime > 300 && Math.abs(diffPageY) < 10) {
                        return;
                    }

                    // 超过边缘滚动有阻力
                    if (movePageY > 0) {
                        movePageY /= 3;
                    } else if (Math.abs(movePageY) > Math.abs(containerOption.scrollHeight)) {
                        movePageY = Math.abs(containerOption.scrollHeight) - Math.abs(movePageY);
                        movePageY = movePageY / 3 - containerOption.scrollHeight;
                    }
                    let transformStyle = 'translate(0, ' + movePageY + 'px)';
                    this.setTransition(columnsType, false, transformStyle);
                }
            },
            touchEndItem(e, containerOption, columnsType) {
                if (containerOption) {
                    containerOption.endTime = parseInt(new Date().getTime());
                    let duration = containerOption.endTime - containerOption.startTime;
                    let touches = e.changedTouches ? e.changedTouches[0] : e;
                    let offsetHeight = touches.pageY - containerOption.startPageY; //本次滚动偏移位置
                    containerOption.offsetTop += offsetHeight; //记录总偏移位置
                    if ((containerOption.offsetTop > 0) || (Math.abs(containerOption.offsetTop) > Math.abs(containerOption.scrollHeight))) {
                        //上边缘&下边缘
                        let transitionStyle = 'all 500ms';
                        this.setTransition(columnsType, true, transitionStyle);
                    } else if (duration < 300) { // 惯性滚动
                        let speed = Math.abs(offsetHeight) / duration; // 惯性移动速度
                        let moveTime = duration * speed * 20; // 惯性滚动时间(动画)
                        moveTime = moveTime > 2000 ? 2000 : moveTime;
                        containerOption.offsetTop += offsetHeight * speed * 10; // 惯性移动距离
                        let transitionStyle = "all " + moveTime + "ms " + "cubic-bezier(0.1, 0.57, 0.1, 1)";
                        this.setTransition(columnsType, true, transitionStyle);
                    } else {
                        // columnControl.transition = 'all 500ms';
                        let transitionStyle = 'all 500ms';
                        this.setTransition(columnsType, true, transitionStyle);
                    }
                    if (containerOption.offsetTop > 0) {
                        containerOption.offsetTop = 0;
                    } else if (Math.abs(containerOption.offsetTop) > Math.abs(containerOption.scrollHeight)) {
                        containerOption.offsetTop = -containerOption.scrollHeight;
                    }

                    // 步长模式
                    if (containerOption.options.step && containerOption.stepLen > 0) {
                        let nowEndY = containerOption.offsetTop;
                        let h = Math.abs(nowEndY % containerOption.stepLen); //滚动多余不足step的高度
                        let halfHeight = containerOption.stepLen / 2; //step一半的高度

                        //超过行一半的高度，则滚动一行
                        let moveY = (h >= halfHeight) ? (nowEndY - containerOption.stepLen + h) : (nowEndY + h);

                        let index = parseInt(Math.abs(moveY) / containerOption.stepLen);
                        this.setSeletedValue(columnsType, index); //设置选中的item值

                        containerOption.offsetTop = moveY;
                    }
                    let transformStyle = 'translate(0, ' + containerOption.offsetTop + 'px)';
                    this.setTransition(columnsType, false, transformStyle);
                    if (this.type.toString() === '1') {
                        let monthMaxDay = this.getMonthMaxDay(this.year, this.month);
                        if (parseInt(this.date) > monthMaxDay) {
                            //超过一个月最长的日期
                            this.date = monthMaxDay;
                            let moveLen = (monthMaxDay - 1) * this.containerOptions.dateContainer.stepLen;
                            this.setScrollTo(3, this.containerOptions.dateContainer, moveLen, 500);
                        }
                    }
                }
            },
            getRangeArray(from, to, formateTwo) {
                let result = [];
                for (let i = from; i <= to; i++) {
                    if (formateTwo) {
                        i = i < 10 ? '0' + i : i.toString(); //小于10的 添加0格式化成两位
                    } else {
                        i = i.toString();
                    }
                    result.push(i);
                }
                return result;
            },
            getDateDetail() {
                let result = { year: '', month: '', date: '' };
                if (this.value) {
                    let dateDetail = this.value.split(this.separator);
                    result.year = dateDetail[0];
                    result.month = dateDetail[1];
                    result.date = dateDetail[2];
                }
                return result;
            },
            getContainerOptions() {
                return {
                    options: {
                        step: true, // 是否开启步长模式
                        defaultPlace: 0 // 默认列表位置
                    },
                    startPageY: 0,
                    startTime: 0,
                    endTime: 0,
                    offsetTop: 0, //上一次滚动位置
                    stepLen: 0, //步长
                    scrollerHeight: 0,
                    scrollHeight: 0,
                    childNodeHeight: 0,
                    itemHeight: 0,
                    transition: '',
                    transform: ''
                }
            },
            getHeights(containerOptions) {
                if (containerOptions) {
                    containerOptions = this.getYearHeight(containerOptions);
                    containerOptions = this.getMonthHeight(containerOptions);
                    if (this.type.toString() === '1') {
                        containerOptions = this.getDateHeight(containerOptions);
                    }
                }
                return containerOptions;
            },
            getYearHeight(containerOptions) {
                if (!containerOptions) {
                    return containerOptions;
                }
                containerOptions.yearContainer.scrollerHeight = this.$refs[this.yearId].clientHeight;
                let yearsNode = this.$refs[this.yearId].childNodes[0];
                let yearNodeHeight = yearsNode.clientHeight;
                let childNodes = yearsNode.childNodes;
                containerOptions.yearContainer.itemHeight = yearNodeHeight;
                containerOptions.yearContainer.scrollHeight = yearNodeHeight - containerOptions.yearContainer.scrollerHeight;
                containerOptions.yearContainer.transition = this.yearTransition;
                containerOptions.yearContainer.transform = this.yearTransform;
                containerOptions.yearContainer.stepLen = childNodes.length > 0 ? childNodes[0].clientHeight : 0;
                return containerOptions;
            },
            getMonthHeight(containerOptions) {
                if (!containerOptions) {
                    return containerOptions;
                }
                containerOptions.monthContainer.scrollerHeight = this.$refs[this.monthId].clientHeight;
                let monthsNode = this.$refs[this.monthId].childNodes[0];
                let monthNodeHeight = monthsNode.clientHeight;
                let childNodes = monthsNode.childNodes;
                containerOptions.monthContainer.itemHeight = monthNodeHeight;
                containerOptions.monthContainer.scrollHeight = monthNodeHeight - containerOptions.monthContainer.scrollerHeight;
                containerOptions.monthContainer.transition = this.yearTransition;
                containerOptions.monthContainer.transform = this.yearTransform;
                containerOptions.monthContainer.stepLen = childNodes.length > 0 ? childNodes[0].clientHeight : 0;
                return containerOptions;
            },
            getDateHeight(containerOptions) {
                if (!containerOptions) {
                    return containerOptions;
                }
                containerOptions.dateContainer.scrollerHeight = this.$refs[this.dateId].clientHeight;
                let datesNode = this.$refs[this.dateId].childNodes[0];
                let dateNodeHeight = datesNode.clientHeight;
                let childNodes = datesNode.childNodes;
                containerOptions.dateContainer.itemHeight = dateNodeHeight;
                containerOptions.dateContainer.scrollHeight = dateNodeHeight - containerOptions.dateContainer.scrollerHeight;
                containerOptions.dateContainer.transition = this.yearTransition;
                containerOptions.dateContainer.transform = this.yearTransform;
                containerOptions.dateContainer.stepLen = childNodes.length > 0 ? childNodes[0].clientHeight : 0;
                return containerOptions;
            },
            setSeletedValue(columnsType, index) {
                switch (columnsType) {
                    case 1:
                        this.year = this.years[index];
                        break;
                    case 2:
                        this.month = this.months[index];
                        break;
                    case 3:
                        this.date = this.dates[index];
                        break;
                }
            },
            setScrollTo(columnsType, containerOption, y, moveTime) {
                if (moveTime && moveTime > 0) {
                    let transitionStyle = "all " + moveTime + "ms " + "cubic-bezier(0.1, 0.57, 0.1, 1)";
                    this.setTransition(columnsType, true, transitionStyle);
                } else {
                    this.setTransition(columnsType, true, 'none');
                }
                y = -y;
                containerOption.offsetTop = y;
                let transformStyle = 'translate(0, ' + y + 'px)';
                this.setTransition(columnsType, false, transformStyle);
            },
            checkLeapYear(year) {
                //校验是否闰年
                if ((year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0)) {
                    return 1;
                }
                return 0;
            },
            getMonthMaxDay(nowYear, nowMonth) {
                //根据选中年份、月份计算当月最长多少天
                if (this.type.toString() === '1') {
                    let leap = this.checkLeapYear(nowYear);
                    let maxMonths = ["01", "03", "05", "07", "08", "10", "12"];

                    let monthMaxDays = 30;
                    if (nowMonth === "02") {
                        monthMaxDays = 28 + leap;
                    } else if (maxMonths.indexOf(nowMonth) > -1) {
                        monthMaxDays = 31;
                    }
                    return monthMaxDays;
                }
            },
            setTransition(columnsType, isTransiton, styleText) {
                switch (columnsType) {
                    case 1:
                        if (isTransiton) {
                            this.yearTransition = styleText;
                        } else {
                            this.yearTransform = styleText;
                        }
                        break;
                    case 2:
                        if (isTransiton) {
                            this.monthTransition = styleText;
                        } else {
                            this.monthTransform = styleText;
                        }
                        break;
                    case 3:
                        if (isTransiton) {
                            this.dateTransition = styleText;
                        } else {
                            this.dateTransform = styleText;
                        }
                        break;
                }
            },
            confirm() {
                let result;
                if (this.type.toString() === '1') {
                    result = [this.year, this.month, this.date].join(this.separator);
                } else {
                    result = [this.year, this.month].join(this.separator);
                }
                this.$emit('confirm', result);
            },
            cancel() {
                this.$emit('cancel');
            }
        }
    };
</script>

<style>
    body {
        -moz-user-select: none;
        -webkit-user-select: none;
        -ms-user-select: none;
        -khtml-user-select: none;
        user-select: none;
    }

    * {
        margin: 0;
        padding: 0;
        -moz-box-sizing: border-box;
        -webkit-box-sizing: border-box;
        box-sizing: border-box;
        -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
        /*-webkit-touch-callout: none;*/
    }

    ul {
        list-style: none outside none;
    }

    .fe-datetimepikcer-wrapper .picker-wrapper  {
        font-size: 16px;
    }

    .fe-datetimepikcer-wrapper .picker-columns  {
        height: 465px;            
    }

    .ub {
        display: -webkit-box !important;
        display: box !important;
        position: relative;
    }

    .ub-f1 {
        position: relative;
        -webkit-box-flex: 1;
        box-flex: 1;
    }

    /*select*/
    .dp_mask {
        overflow: hidden;
        font-size: 15px;
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        height: 100%;
        width: 100%;
        background: rgba(0, 0, 0, 0);
        z-index: 9998;
    }

    .dp_select {
        font-size: 15px;
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        width: 100%;
        color: #333;
        background: #D1D5D8;
        z-index: 9999;
        -webkit-transition: 300ms all;
        transition: 300ms all;
    }

    .dp_select>header {
        overflow: hidden;
        width: 100%;
        height: 65px;
        line-height: 65px;
        text-align: center;
        background: #F0F1F2;
        -webkit-box-shadow: 0 0 8px #333;
        -moz-box-shadow: 0 0 8px #333;
        box-shadow: 0 0 8px #333;
    }

    .dp_select>header>h1 {
        display: inline-block;
        font-size: 15px;
        font-weight: normal;
    }

    .dp_select>header>button {
        font-size: 26px;
        height: 65px;
        padding: 0 10px;
        border: none;
        outline: none;
        color: #007AFF;
        background: #F0F1F2;
    }

    .dp_select button.nav_left {
        float: left;
    }

    .dp_select button.nav_right {
        float: right;
    }

    .dp_select>p {
        width: 100%;
        line-height: 30px;
        text-align: center;
        font-size: 14px !important;
    }

    .dp_select>p>span {
        display: block;
    }

    /*列表*/
    .dp_select>div {
        overflow: hidden;
        position: relative;
        height: 400px;
        text-align: center;
    }

    .dp_select>div>div.ub-f1 {
        /* max-width: 100%;
        min-width: 100%; */
        width:33%;
    }

    .dp_select ul {
        line-height: 40px;
    }

    .dp_select ul>li {
        height: 40px;
        color: #2A2B2C;
        padding: 0 10px !important;
        margin: 0 !important;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    
    .dp_select .sel_middle {
        position: absolute;
        top: 25%;
        left: 0;
        width: 100%;
        height: 40px;
        margin-top: -20px;
        pointer-events: none;
        border-top: 1px solid #aaa;
        border-bottom: 1px solid #aaa;
    }

    .dp_select .sel_top {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 80px;
        pointer-events: none;
        background: rgba(209, 213, 216, 0.7);
    }

    .dp_select .sel_bottom {
        position: absolute;
        left: 0;
        bottom: 0;
        width: 100%;
        height: 80px;
        pointer-events: none;
        background: rgba(209, 213, 216, 0.7);
    }
</style>